home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 60 / IOPROG_60.ISO / soft / c++ / gsl-1.1.1-setup.exe / {app} / src / ode-initval / bsimp.c next >
Encoding:
C/C++ Source or Header  |  2002-04-18  |  12.6 KB  |  523 lines

  1. /* ode-initval/bsimp.c
  2.  * 
  3.  * Copyright (C) 1996, 1997, 1998, 1999, 2000 Gerard Jungman
  4.  * 
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or (at
  8.  * your option) any later version.
  9.  * 
  10.  * This program is distributed in the hope that it will be useful, but
  11.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.  * General Public License for more details.
  14.  * 
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20. /* Bulirsch-Stoer Implicit */
  21.  
  22. /* Author:  G. Jungman
  23.  */
  24. /* Bader-Deuflhard implicit extrapolative stepper.
  25.  * [Numer. Math., 41, 373 (1983)]
  26.  */
  27. #include <config.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <gsl/gsl_math.h>
  31. #include <gsl/gsl_errno.h>
  32. #include <gsl/gsl_linalg.h>
  33. #include <gsl/gsl_odeiv.h>
  34.  
  35. #include "odeiv_util.h"
  36.  
  37. #define SEQUENCE_COUNT 8
  38. #define SEQUENCE_MAX   7
  39.  
  40. /* Bader-Deuflhard extrapolation sequence */
  41. static const int bd_sequence[SEQUENCE_COUNT] =
  42.   { 2, 6, 10, 14, 22, 34, 50, 70 };
  43.  
  44. typedef struct
  45. {
  46.   gsl_matrix *d;        /* workspace for extrapolation         */
  47.   gsl_matrix *a_mat;        /* workspace for linear system matrix  */
  48.   gsl_permutation *p_vec;    /* workspace for LU permutation        */
  49.  
  50.   double x[SEQUENCE_MAX];    /* workspace for extrapolation */
  51.  
  52.   /* state info */
  53.   size_t k_current;
  54.   size_t k_choice;
  55.   double h_next;
  56.   double eps;
  57.  
  58.   /* workspace for extrapolation step */
  59.   double *yp;
  60.   double *y_extrap_save;
  61.   double *y_extrap_sequence;
  62.   double *extrap_work;
  63.   double *dfdt;
  64.   double *y_temp;
  65.   double *delta_temp;
  66.   double *weight;
  67.   gsl_matrix *dfdy;
  68.  
  69.   /* workspace for the basic stepper */
  70.   double *rhs_temp;
  71.   double *delta;
  72.  
  73.   /* order of last step */
  74.   size_t order;
  75. }
  76. bsimp_state_t;
  77.  
  78. /* Compute weighting factor */
  79.  
  80. static void
  81. compute_weights (const double y[], double w[], size_t dim)
  82. {
  83.   size_t i;
  84.   for (i = 0; i < dim; i++)
  85.     {
  86.       double u = fabs(y[i]);
  87.       w[i] = (u > 0.0) ? u : 1.0;
  88.     }
  89. }
  90.  
  91. /* Calculate a choice for the "order" of the method, using the
  92.  * Deuflhard criteria.  
  93.  */
  94.  
  95. static size_t
  96. bsimp_deuf_kchoice (double eps, size_t dimension)
  97. {
  98.   const double safety_f = 0.25;
  99.   const double small_eps = safety_f * eps;
  100.  
  101.   double a_work[SEQUENCE_COUNT];
  102.   double alpha[SEQUENCE_MAX][SEQUENCE_MAX];
  103.  
  104.   int i, k;
  105.  
  106.   a_work[0] = bd_sequence[0] + 1.0;
  107.  
  108.   for (k = 0; k < SEQUENCE_MAX; k++)
  109.     {
  110.       a_work[k + 1] = a_work[k] + bd_sequence[k + 1];
  111.     }
  112.  
  113.   for (i = 0; i < SEQUENCE_MAX; i++)
  114.     {
  115.       alpha[i][i] = 1.0;
  116.       for (k = 0; k < i; k++)
  117.     {
  118.       const double tmp1 = a_work[k + 1] - a_work[i + 1];
  119.       const double tmp2 = (a_work[i + 1] - a_work[0] + 1.0) * (2 * k + 1);
  120.       alpha[k][i] = pow (small_eps, tmp1 / tmp2);
  121.     }
  122.     }
  123.  
  124.   a_work[0] += dimension;
  125.  
  126.   for (k = 0; k < SEQUENCE_MAX; k++)
  127.     {
  128.       a_work[k + 1] = a_work[k] + bd_sequence[k + 1];
  129.     }
  130.  
  131.   for (k = 0; k < SEQUENCE_MAX - 1; k++)
  132.     {
  133.       if (a_work[k + 2] > a_work[k + 1] * alpha[k][k + 1])
  134.     break;
  135.     }
  136.  
  137.   return k;
  138. }
  139.  
  140. static void
  141. poly_extrap (gsl_matrix * d,
  142.          const double x[],
  143.          const unsigned int i_step,
  144.          const double x_i,
  145.          const double y_i[],
  146.          double y_0[], double y_0_err[], double work[], const size_t dim)
  147. {
  148.   size_t j, k;
  149.  
  150.   DBL_MEMCPY (y_0_err, y_i, dim);
  151.   DBL_MEMCPY (y_0, y_i, dim);
  152.  
  153.   if (i_step == 0)
  154.     {
  155.       for (j = 0; j < dim; j++)
  156.     {
  157.       gsl_matrix_set (d, 0, j, y_i[j]);
  158.     }
  159.     }
  160.   else
  161.     {
  162.       DBL_MEMCPY (work, y_i, dim);
  163.  
  164.       for (k = 0; k < i_step; k++)
  165.     {
  166.       double delta = 1.0 / (x[i_step - k - 1] - x_i);
  167.       const double f1 = delta * x_i;
  168.       const double f2 = delta * x[i_step - k - 1];
  169.  
  170.       for (j = 0; j < dim; j++)
  171.         {
  172.           const double q_kj = gsl_matrix_get (d, k, j);
  173.           gsl_matrix_set (d, k, j, y_0_err[j]);
  174.           delta = work[j] - q_kj;
  175.           y_0_err[j] = f1 * delta;
  176.           work[j] = f2 * delta;
  177.           y_0[j] += y_0_err[j];
  178.         }
  179.     }
  180.  
  181.       for (j = 0; j < dim; j++)
  182.     {
  183.       gsl_matrix_set (d, i_step, j, y_0_err[j]);
  184.     }
  185.     }
  186. }
  187.  
  188. /* Basic implicit Bulirsch-Stoer step.  Divide the step h_total into
  189.  * n_step smaller steps and do the Bader-Deuflhard semi-implicit
  190.  * iteration.  */
  191.  
  192. static int
  193. bsimp_step_local (void *vstate,
  194.           size_t dim,
  195.           const double t0,
  196.           const double h_total,
  197.           const unsigned int n_step,
  198.           const double y[],
  199.           const double yp[],
  200.           const double dfdt[],
  201.           const gsl_matrix * dfdy,
  202.           double y_out[], 
  203.                   const gsl_odeiv_system * sys)
  204. {
  205.   bsimp_state_t *state = (bsimp_state_t *) vstate;
  206.  
  207.   gsl_matrix *const a_mat = state->a_mat;
  208.   gsl_permutation *const p_vec = state->p_vec;
  209.  
  210.   double *const delta = state->delta;
  211.   double *const y_temp = state->y_temp;
  212.   double *const delta_temp = state->delta_temp;
  213.   double *const rhs_temp = state->rhs_temp;
  214.   double *const w = state->weight;
  215.  
  216.   gsl_vector_view y_temp_vec = gsl_vector_view_array (y_temp, dim);
  217.   gsl_vector_view delta_temp_vec = gsl_vector_view_array (delta_temp, dim);
  218.   gsl_vector_view rhs_temp_vec = gsl_vector_view_array (rhs_temp, dim);
  219.  
  220.   const double h = h_total / n_step;
  221.   double t = t0 + h;
  222.  
  223.   double sum;
  224.  
  225.   /* This is the factor sigma referred to in equation 3.4 of the
  226.      paper.  A relative change in y exceeding sigma indicates a
  227.      runaway behavior. According to the authors suitable values for
  228.      sigma are >>1.  I have chosen a value of 100*dim. BJG */
  229.  
  230.   const double max_sum = 100.0 * dim;
  231.  
  232.   int signum;
  233.   size_t i, j;
  234.   size_t n_inter;
  235.  
  236.   /* Calculate the matrix for the linear system. */
  237.   for (i = 0; i < dim; i++)
  238.     {
  239.       for (j = 0; j < dim; j++)
  240.     {
  241.       gsl_matrix_set (a_mat, i, j, -h * gsl_matrix_get (dfdy, i, j));
  242.     }
  243.       gsl_matrix_set (a_mat, i, i, gsl_matrix_get (a_mat, i, i) + 1.0);
  244.     }
  245.  
  246.   /* LU decomposition for the linear system. */
  247.  
  248.   gsl_linalg_LU_decomp (a_mat, p_vec, &signum);
  249.  
  250.   /* Compute weighting factors */
  251.  
  252.   compute_weights (y, w, dim);
  253.  
  254.   /* Initial step. */
  255.  
  256.   for (i = 0; i < dim; i++)
  257.     {
  258.       y_temp[i] = h * (yp[i] + h * dfdt[i]);
  259.     }
  260.  
  261.   gsl_linalg_LU_solve (a_mat, p_vec, &y_temp_vec.vector, &delta_temp_vec.vector);
  262.  
  263.   sum = 0.0;
  264.  
  265.   for (i = 0; i < dim; i++)
  266.     {
  267.       const double di = delta_temp[i];
  268.       delta[i] = di;
  269.       y_temp[i] = y[i] + di;
  270.       sum += fabs(di) / w[i];
  271.     }
  272.  
  273.   if (sum > max_sum) 
  274.     {
  275.       return GSL_EFAILED ;
  276.     }
  277.  
  278.   /* Intermediate steps. */
  279.  
  280.   GSL_ODEIV_FN_EVAL (sys, t, y_temp, y_out);
  281.  
  282.   for (n_inter = 1; n_inter < n_step; n_inter++)
  283.     {
  284.       for (i = 0; i < dim; i++)
  285.     {
  286.       rhs_temp[i] = h * y_out[i] - delta[i];
  287.     }
  288.  
  289.       gsl_linalg_LU_solve (a_mat, p_vec, &rhs_temp_vec.vector, &delta_temp_vec.vector);
  290.  
  291.       sum = 0.0;
  292.  
  293.       for (i = 0; i < dim; i++)
  294.     {
  295.       delta[i] += 2.0 * delta_temp[i];
  296.       y_temp[i] += delta[i];
  297.           sum += fabs(delta[i]) / w[i];
  298.     }
  299.  
  300.       if (sum > max_sum) 
  301.         {
  302.           return GSL_EFAILED ;
  303.         }
  304.  
  305.       t += h;
  306.  
  307.       GSL_ODEIV_FN_EVAL (sys, t, y_temp, y_out);
  308.     }
  309.  
  310.  
  311.   /* Final step. */
  312.  
  313.   for (i = 0; i < dim; i++)
  314.     {
  315.       rhs_temp[i] = h * y_out[i] - delta[i];
  316.     }
  317.  
  318.   gsl_linalg_LU_solve (a_mat, p_vec, &rhs_temp_vec.vector, &delta_temp_vec.vector);
  319.  
  320.   sum = 0.0;
  321.  
  322.   for (i = 0; i < dim; i++)
  323.     {
  324.       y_out[i] = y_temp[i] + delta_temp[i];
  325.       sum += fabs(delta_temp[i]) / w[i];
  326.     }
  327.  
  328.   if (sum > max_sum) 
  329.     {
  330.       return GSL_EFAILED ;
  331.     }
  332.  
  333.   return GSL_SUCCESS;
  334. }
  335.  
  336.  
  337. static void *
  338. bsimp_alloc (size_t dim)
  339. {
  340.   bsimp_state_t *state = (bsimp_state_t *) malloc (sizeof (bsimp_state_t));
  341.  
  342.   state->d = gsl_matrix_alloc (SEQUENCE_MAX, dim);
  343.   state->a_mat = gsl_matrix_alloc (dim, dim);
  344.   state->p_vec = gsl_permutation_alloc (dim);
  345.  
  346.   state->yp = (double *) malloc (dim * sizeof (double));
  347.   state->y_extrap_save = (double *) malloc (dim * sizeof (double));
  348.   state->y_extrap_sequence = (double *) malloc (dim * sizeof (double));
  349.   state->extrap_work = (double *) malloc (dim * sizeof (double));
  350.   state->dfdt = (double *) malloc (dim * sizeof (double));
  351.   state->y_temp = (double *) malloc (dim * sizeof (double));
  352.   state->delta_temp = (double *) malloc (dim * sizeof(double));
  353.   state->weight = (double *) malloc (dim * sizeof(double));
  354.  
  355.   state->dfdy = gsl_matrix_alloc (dim, dim);
  356.  
  357.   state->rhs_temp = (double *) malloc (dim * sizeof(double));
  358.   state->delta = (double *) malloc (dim * sizeof (double));
  359.  
  360.   {
  361.     size_t k_choice = bsimp_deuf_kchoice (GSL_SQRT_DBL_EPSILON, dim); /*FIXME: choice of epsilon? */
  362.     state->k_choice = k_choice;
  363.     state->k_current = k_choice;
  364.     state->order = 2 * k_choice;
  365.   }
  366.  
  367.   state->h_next = -GSL_SQRT_DBL_MAX;
  368.  
  369.   return state;
  370. }
  371.  
  372. /* Perform the basic semi-implicit extrapolation
  373.  * step, of size h, at a Deuflhard determined order.
  374.  */
  375. static int
  376. bsimp_apply (void *vstate,
  377.              size_t dim,
  378.              const double t,
  379.              const double h,
  380.              double y[],
  381.              double yerr[],
  382.              const double dydt_in[],
  383.              double dydt_out[], 
  384.              const gsl_odeiv_system * sys)
  385. {
  386.   bsimp_state_t *state = (bsimp_state_t *) vstate;
  387.  
  388.   double *const x = state->x;
  389.   double *const yp = state->yp;
  390.   double *const y_extrap_sequence = state->y_extrap_sequence;
  391.   double *const y_extrap_save = state->y_extrap_save;
  392.   double *const extrap_work = state->extrap_work;
  393.   double *const dfdt = state->dfdt;
  394.   gsl_matrix *d = state->d;
  395.   gsl_matrix *dfdy = state->dfdy;
  396.  
  397.   const double t_local = t;
  398.  
  399.   size_t i, k;
  400.  
  401.   if (h + t_local == t_local)
  402.     {
  403.       return GSL_EUNDRFLW;    /* FIXME: error condition */
  404.     }
  405.  
  406.   DBL_MEMCPY (y_extrap_save, y, dim);
  407.   
  408.   /* Evaluate the derivative. */
  409.   if (dydt_in != NULL)
  410.     {
  411.       DBL_MEMCPY (yp, dydt_in, dim);
  412.     }
  413.   else
  414.     {
  415.       GSL_ODEIV_FN_EVAL (sys, t_local, y, yp);
  416.     }
  417.  
  418.   /* Evaluate the Jacobian for the system. */
  419.   GSL_ODEIV_JA_EVAL (sys, t_local, y, dfdy->data, dfdt);
  420.  
  421.   /* Make a series of refined extrapolations,
  422.    * up to the specified maximum order, which
  423.    * was calculated based on the Deuflhard
  424.    * criterion upon state initialization.  */
  425.   for (k = 0; k <= state->k_current; k++)
  426.     {
  427.       const unsigned int N = bd_sequence[k];
  428.       const double r = (h / N);
  429.       const double x_k = r * r;
  430.  
  431.       int status = bsimp_step_local (state,
  432.                                      dim, t_local, h, N,
  433.                                      y_extrap_save, yp,
  434.                                      dfdt, dfdy,
  435.                                      y_extrap_sequence, 
  436.                                      sys);
  437.  
  438.       if (status != GSL_SUCCESS)
  439.         {
  440.           /* If the local step fails, set the error to infinity in
  441.              order to force a reduction in the step size */
  442.  
  443.           for (i = 0; i < dim; i++)
  444.             {
  445.               yerr[i] = GSL_POSINF;
  446.             }
  447.  
  448.           break;
  449.         }
  450.  
  451.       x[k] = x_k;
  452.  
  453.       poly_extrap (d, x, k, x_k, y_extrap_sequence, y, yerr, extrap_work, dim);
  454.     }
  455.  
  456.   /* Evaluate dydt_out[]. */
  457.  
  458.   if (dydt_out != NULL)
  459.     {
  460.       GSL_ODEIV_FN_EVAL (sys, t + h, y, dydt_out);
  461.     }
  462.  
  463.   return GSL_SUCCESS;
  464. }
  465.  
  466. static unsigned int
  467. bsimp_order (void *vstate)
  468. {
  469.   bsimp_state_t *state = (bsimp_state_t *) vstate;
  470.   return state->order;
  471. }
  472.  
  473. static int
  474. bsimp_reset (void *vstate, size_t dim)
  475. {
  476.   bsimp_state_t *state = (bsimp_state_t *) vstate;
  477.  
  478.   state->h_next = 0;
  479.  
  480.   DBL_ZERO_MEMSET (state->yp, dim);
  481.  
  482.   return GSL_SUCCESS;
  483. }
  484.  
  485.  
  486. static void
  487. bsimp_free (void * vstate)
  488. {
  489.   bsimp_state_t *state = (bsimp_state_t *) vstate;
  490.  
  491.   free (state->delta);
  492.   free (state->rhs_temp);
  493.  
  494.   gsl_matrix_free (state->dfdy);
  495.  
  496.   free (state->weight);
  497.   free (state->delta_temp);
  498.   free (state->y_temp);
  499.   free (state->dfdt);
  500.   free (state->extrap_work);
  501.   free (state->y_extrap_sequence);
  502.   free (state->y_extrap_save);
  503.   free (state->yp);
  504.  
  505.   gsl_permutation_free (state->p_vec);
  506.   gsl_matrix_free (state->a_mat);
  507.   gsl_matrix_free (state->d);
  508.   free (state);
  509. }
  510.  
  511. static const gsl_odeiv_step_type bsimp_type = { 
  512.   "bsimp",                    /* name */
  513.   1,                /* can use dydt_in */
  514.   0,                /* gives exact dydt_out */
  515.   &bsimp_alloc,
  516.   &bsimp_apply,
  517.   &bsimp_reset,
  518.   &bsimp_order,
  519.   &bsimp_free
  520. };
  521.  
  522. const gsl_odeiv_step_type *gsl_odeiv_step_bsimp = &bsimp_type;
  523.